﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

namespace Neto;

/// <summary>
///     动态调用方法
/// </summary>
public static class InvokeHelper
{
    /// <summary>
    ///     注册方法集合
    /// </summary>
    /// <example>
    ///     <接口的type，<唯一名称： 接口类型名称+ 方法名+ 参数个数， InvokeRegisterObject>>
    /// </example>
    public static ConcurrentDictionary<Type, ConcurrentDictionary<string, InvokeRegisterObject>> RegisterMethodInfos =
        new();

    /// <summary>
    ///     注册方法
    /// </summary>
    /// <param name="type">接口interface 的type</param>
    /// <param name="methodName">方法名列表</param>
    /// <param name="parsCount">参数个数</param>
    public static void Register(Type type, string methodName, int parsCount = 0)
    {
        try
        {
            //查找所有实现了 type（接口）的类
            var appTypes = App.EffectiveTypes.Where(u => u.GetInterfaces()
                .Any(i => i.HasImplementsGeneric(type)))?.ToList();
            if (appTypes == null) return;
            //实现类的方法信息
            var appRegister = new ConcurrentDictionary<string, InvokeRegisterObject>();

            var name = GetIndexName(type, methodName, parsCount);
            if (RegisterMethodInfos.TryGetValue(type, out var info)) appRegister = info;

            var method = type
                .GetMethods(BindingFlags.Public | BindingFlags.Instance)
                .FirstOrDefault(u => u.Name == methodName && u.GetParameters().Length == parsCount);

            if (method != null)
                appRegister.TryAdd(name, new InvokeRegisterObject(name, type, appTypes, parsCount, method));

            //如果存在，移除
            if (RegisterMethodInfos.ContainsKey(type)) RegisterMethodInfos.TryRemove(type, out _);

            RegisterMethodInfos.AddOrUpdate(type, appRegister);
        }
        catch (Exception ex)
        {
            LogX.Error($"type:{type.FullName} methodName:{methodName}，\r\n异常：{ex.ToStringEx()}",
                "Neto\\Invoke\\Register");
        }
    }

    /// <summary>
    ///     获取唯一名称
    /// </summary>
    /// <param name="type"></param>
    /// <param name="methodName"></param>
    /// <param name="parsCount"></param>
    /// <returns></returns>
    private static string GetIndexName(Type type, string methodName, int parsCount = 0)
    {
        return $"{type.Name}_{methodName}_{parsCount}";
    }


    /// <summary>
    ///     根据 Interface 的type 获取监听方法
    /// </summary>
    /// <param name="type">Interface 的type </param>
    /// <returns></returns>
    public static ConcurrentDictionary<string, InvokeRegisterObject> GetMethods(Type type)
    {
        if (RegisterMethodInfos.TryGetValue(type, out var methods))
            return methods;
        return new ConcurrentDictionary<string, InvokeRegisterObject>();
    }

    /// <summary>
    ///     根据 Interface 的type 获取监听方法
    /// </summary>
    /// <param name="type">Interface 的type </param>
    /// <param name="methodName">方法名,区分大小写</param>
    /// <param name="parsCount">参数个数</param>
    /// <returns></returns>
    public static InvokeRegisterObject GetMethod(Type type, string methodName, int parsCount = 0)
    {
        if (!RegisterMethodInfos.TryGetValue(type, out var methods)) return null;
        var indexName = GetIndexName(type, methodName, parsCount);
        return methods.TryGetValue(indexName, out var method) ? method : null;
    }

    /// <summary>
    ///     执行注册的方法
    /// </summary>
    /// <param name="type">Interface 的type</param>
    /// <param name="methodName">方法名,区分大小写</param>
    /// <param name="parsCount">参数个数</param>
    /// <param name="args">参数</param>
    public static void Execute(Type type, string methodName, int parsCount = 0, object[]? args = null)
    {
        //如果方法名为空，则不执行
        if (string.IsNullOrWhiteSpace(methodName))
        {
            LogX.Error($"type:{type.FullName} methodName:{methodName} 为空，\r\n参数：{args.ToJson2()}",
                "Neto\\Invoke\\Execute");
            return;
        }

        var registerObject = GetMethod(type, methodName, parsCount);
        if (registerObject == null) return;
        //遍历实现类
        foreach (var achieveType in registerObject.AchieveTypes)
            try
            {
                var instance = Activator.CreateInstance(achieveType);
                registerObject.MethodInfo.Invoke(instance, args);
            }
            catch (Exception ex)
            {
                LogX.Error(ex, "Neto\\Invoke\\Execute");
            }
    }

    /// <summary>
    ///     执行注册的方法
    ///     注意：仅支持只有一个实现类
    /// </summary>
    /// <param name="type">Interface 的type</param>
    /// <param name="methodName">方法名,区分大小写</param>
    /// <param name="parsCount">参数个数</param>
    /// <param name="args">参数</param>
    public static TResult? ExecuteReturn<TResult>(Type type, string methodName, int parsCount = 0,
        object[]? args = null)
    {
        //如果方法名为空，则不执行
        if (string.IsNullOrWhiteSpace(methodName))
        {
            LogX.Error($"type:{type.FullName} methodName:{methodName} 为空，\r\n参数：{args.ToJson2()}",
                "Neto\\Invoke\\ExecuteByOne");
            return default;
        }

        var registerObject = GetMethod(type, methodName, parsCount);
        if (registerObject == null) return default;
        //遍历实现类
        foreach (var achieveType in registerObject.AchieveTypes)
            try
            {
                var instance = Activator.CreateInstance(achieveType);
                var result = registerObject.MethodInfo.Invoke(instance, args);
                return (TResult)result;
            }
            catch (Exception ex)
            {
                LogX.Error(ex, "Neto\\Invoke\\Execute");
            }

        return default;
    }
}